package com.robot.backend.utils.gameMap;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;

import com.alibaba.fastjson2.JSONObject;
import com.robot.backend.consumer.WebSocketServer;
import com.robot.backend.mapper.RecordMapper;
import com.robot.backend.mapper.UserMapper;
import com.robot.backend.pojo.Robot;
import com.robot.backend.pojo.User;
import com.robot.backend.service.impl.record.recordCRUDServiceImpl;
import com.robot.backend.utils.gameMap.player;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import com.robot.backend.service.record.recordCRUDService;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.robot.backend.utils.gameMap.serviceTest.test;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;


public class game extends Thread{//game线程主要维护在后端同步执行一个游戏，负责计算游戏信息，前端只画动画
    recordCRUDService recordCRUDService;
    final private Integer rows;
    final private Integer cols;
    final private Integer inner_walls_count;
    final public int[][] g;
    final private static int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1};

    private player player1 = new player();
    private player player2 = new player();

    private Integer nextStep1 = null;
    private Integer nextStep2 = null;
    private String status = "playing";
    private String lose = null;
    public int[][] gRes = new int[15][15];

    private int det = 0;

    private ReentrantLock lock = new ReentrantLock();
    public game(Integer rows, Integer cols, Integer inner_walls_count,int id1,int id2) {
        this.rows = rows;
        this.cols = cols;
        this.inner_walls_count = inner_walls_count;
        this.g = new int[rows][cols];
        player1 = new player(id1,rows-2,1,new ArrayList<>(),new ArrayList<>(),0,0,0,0,0);
        player2 = new player(id2,1,cols-2,new ArrayList<>(),new ArrayList<>(),0,0,0,0,0);
    }
    public player getPlayer1(){
        return player1;
    }
    public player getPlayer2(){
        return player2;
    }

    public void setBotId(int id,int botId){
        if(player1.getId() == id) player1.setBotid(botId);
        else player2.setBotid(botId);
    }
    public void setDeta(int d){
        this.det = d;
    }
    public int[][] getG() {
        return g;
    }

    private boolean check_connectivity(int sx, int sy, int tx, int ty) {
        if (sx == tx && sy == ty) return true;
        g[sx][sy] = 1;

        for (int i = 0; i < 4; i ++ ) {
            int x = sx + dx[i], y = sy + dy[i];
            if (x >= 0 && x < this.rows && y >= 0 && y < this.cols && g[x][y] == 0) {
                if (check_connectivity(x, y, tx, ty)) {
                    g[sx][sy] = 0;
                    return true;
                }
            }
        }

        g[sx][sy] = 0;
        return false;
    }

    private boolean draw() {  // 画地图
        for (int i = 0; i < this.rows; i ++ ) {
            for (int j = 0; j < this.cols; j ++ ) {
                g[i][j] = 0;
            }
        }

        for (int r = 0; r < this.rows; r ++ ) {
            g[r][0] = g[r][this.cols - 1] = 1;
        }
        for (int c = 0; c < this.cols; c ++ ) {
            g[0][c] = g[this.rows - 1][c] = 1;
        }

        Random random = new Random();
        for (int i = 0; i < this.inner_walls_count / 2; i ++ ) {
            for (int j = 0; j < 1000; j ++ ) {
                int r = random.nextInt(this.rows);
                int c = random.nextInt(this.cols);

                if (g[r][c] == 1 || g[this.rows - 1 - r][this.cols - 1 - c] == 1)
                    continue;
                if (r == this.rows - 2 && c == 1 || r == 1 && c == this.cols - 2)
                    continue;

                g[r][c] = g[this.rows - 1 - r][this.cols - 1 - c] = 1;
                break;
            }
        }

        return check_connectivity(this.rows - 2, 1, 1, this.cols - 2);
    }

    public void createMap() {//创建1000次，直到存在一个存在通路的地图
        for (int i = 0; i < 1000; i ++ ) {
            if (draw())
                break;
        }
    }
    public void setStepA(Integer nextStep){
        lock.lock();
        try {
            this.nextStep1 = nextStep;
        }finally {
            lock.unlock();
        }
    }
    public void setStepB(Integer nextStep){
        lock.lock();
        try {
            this.nextStep2 = nextStep;
        }finally {
            lock.unlock();
        }

    }
    private boolean nextStep(){//等待下一步操作
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //boolean haveSend1 = false,haveSend2 = false;
        sendBotCode(player1);
        sendBotCode(player2);
        for(int i=0;i<50;i++){//等待5秒，5秒没输入则失败

            try {
                Thread.sleep(100);//轮询，100ms一次，轮询50次
                lock.lock();
                try{
//                    if(haveSend1 == false)
//                    {
//                        //发送代码执行一次
//                        ;//发送bot代码,每次执行完后都发一次,只发一次
//                        haveSend1 = true;
//                    }
//                    if(haveSend2 == false){
//
//                        haveSend2 = true;
//                    }
                    if(nextStep1 != null && nextStep2 !=null) {
                        player1.getStep().add(nextStep1);
                        player2.getStep().add(nextStep2);
//                        haveSend1 = false;//重置下一次
//                        haveSend2 = false;
                        return true;
                    }
                }finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return false;
    }
    public void updateMap(int x,int y,int state,int uid){//将蛇走过的路径也看做障碍,返回到running微服务,0代表添加，1删除
        if(state == 0) {
            g[x][y] = 1;
        }
        else g[x][y] = 0;
    }
    private void sendMessage(String message){//通用广播信息
        WebSocketServer.users.get(player1.getId()).sendMessage(message);
        WebSocketServer.users.get(player2.getId()).sendMessage(message);
    }

    private int scoreCnt(){//计算加分
        int Kmax = 100;//上限
        int Kbase = 50;//幅度

        if(det == 0) return Kmax;
        int sc = (Kmax*Kbase) / det;
        System.out.println("加分"+sc);
        return Math.min(sc, det);
    }
    private void sendRes(){//发送结果,并记录到数据库
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("event","result");
        jsonObject.put("loser",lose);
        String loseId = "";
        if(lose.equals("1")) loseId = String.valueOf(player1.getId());
        if(lose.equals("2")) loseId = String.valueOf(player2.getId());
        if(lose.equals("all")) loseId = lose;
        WebSocketServer.users.get(player1.getId()).cancelBotUserBind(player1.getId());
        WebSocketServer.users.get(player2.getId()).cancelBotUserBind(player2.getId());
        int sc = scoreCnt();
        //String loser = String.valueOf(player1.getId());
//        recordCRUDService.addRecord(player1.getId(), player2.getId(),1,1,loser, player1.getStep().stream().mapToInt(Integer::intValue).toArray(),
//                player2.getStep().stream().mapToInt(Integer::intValue).toArray(),g, player1.getSx(),player2.getSy(),player1.getSx(), player1.getSy());
        //普通类不能直接调用service
        //后期这里直接再算一遍得分
        //开始游戏时，返回加分，结束游戏时，记录加分


        test.get(player1.getId(), player2.getId(),player1.getBotid(),player2.getBotid(),loseId, player1.getStep().stream().mapToInt(Integer::intValue).toArray(),
                player2.getStep().stream().mapToInt(Integer::intValue).toArray(),gRes, player1.getSx(),player2.getSy(),player1.getSx(), player1.getSy(),sc,-sc);
        sendMessage(jsonObject.toJSONString());
    }
    private void sendMove() {//传递移动信息
        JSONObject jsonObject = new JSONObject();
        lock.lock();
        try {
            jsonObject.put("event", "move");
            jsonObject.put("direction1", nextStep1);
            jsonObject.put("direction2", nextStep2);
            sendMessage(jsonObject.toJSONString());
            nextStep1 = nextStep2 = null;
        } finally {
            lock.unlock();
        }
    }
    private void sendBotCode(player player){//发送代码执行
        System.out.println("发送代码");
        if(player.getBotid() == 0) return;//亲自,不用发
        player opponent = new player();
        if(player.getId() == player1.getId())
            opponent = player2;
        else opponent = player2;
        player1.getHead();
        player2.getHead();
        Robot robot = WebSocketServer.robotMapper.selectById(player.getBotid());
        String botCode = robot.getContent();
        MultiValueMap<String,String> map = new LinkedMultiValueMap<>();
        map.add("id", String.valueOf(player.getBotid()));
        map.add("uid",String.valueOf(player.getId()));
        map.add("botCode",botCode);
        map.add("map", Arrays.deepToString(g));
        map.add("myX", String.valueOf(player.getHx()));
        map.add("myY", String.valueOf(player.getHy()));
        map.add("oppoX", String.valueOf(opponent.getSx()));
        map.add("oppoY", String.valueOf(opponent.getSy()));
        map.add("steps", player.getStep().toString());
        map.add("lang",robot.getLang());

        String pos = "";
        if(player.equals(player1)) pos = "l";
        else pos="r";//出生位置
        map.add("pos",pos);
        WebSocketServer.restTemplate.postForObject(WebSocketServer.addBotURL,map,String.class);
    }

    private boolean checkValid(List<cell> cellsA, List<cell> cellsB) {
        int n = cellsA.size();
        cell cell = cellsA.get(n - 1);
        try{
            if (g[cell.x][cell.y] == 1) return false;
        }catch (Exception e){
            return false;
        }
        for (int i = 0; i < n - 1; i ++ ) {
            if (cellsA.get(i).x == cell.x && cellsA.get(i).y == cell.y)
                return false;
        }

        for (int i = 0; i < n - 1; i ++ ) {
            if (cellsB.get(i).x == cell.x && cellsB.get(i).y == cell.y)
                return false;
        }

        return true;
    }

    private void judge(){//判断操作是否合法
        List<cell> cellsA =player1.getCells();
        List<cell> cellsB =player2.getCells();
        boolean validA = checkValid(cellsA, cellsB);
        boolean validB = checkValid(cellsB, cellsA);
        if (!validA || !validB) {
            status = "finished";
            if (!validA && !validB) {
                lose = "all";
            } else if (!validA) {
                lose = "1";
            } else {
                lose = "2";
            }
        }
        //判断完操作是否合法后，更新地图，直接将蛇头位置设为1
//        player1.updateMap();
//        player2.updateMap();
    }
    @Override
    public void run() {//检查线程，最多检查长度1000
        for(int i =0 ;i<1000;i++){
            if(nextStep()){//是否获取操作
                judge();//检查完之后更新地图
                player1.updateMap();
                player2.updateMap();
                if(status.equals("playing")) sendMove();
                else {sendRes();break;};//撞墙了
            }else{
                status = "finish";
                lock.lock();
                try{
                    if(nextStep1 == null && nextStep2 == null)
                        lose = "all";
                    else if(nextStep1 == null) lose = "1";
                    else lose = "2";
                }finally {
                    lock.unlock();
                }
                sendRes();
                break;
            }
        }
    }
}
